// ==UserScript==
// @name         b站首页直播查看优化
// @namespace    http://tampermonkey.net/
// @version      1.0.2
// @description   首页动态直播展示优化
// @author       口吃者
// @match        https://www.bilibili.com/
// @match        https://www.bilibili.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=bilibili.com
// @run-at document-end
// @grant        none
// @license MIT
// ==/UserScript==
/* 
    1. 动态mouseenter状态时，重新请求获取一次数据，避免每次更新都需要点刷新
    2. 原先最大只可以显示5条，现在追加显示剩下的全部
*/
const live_up_list_url = "https://api.bilibili.com/x/polymer/web-dynamic/v1/live-up";
const ifLoadOk = false;
let currentIntervalId; // 用于存储当前的定时器 ID
let ups = [];
let singleUpHtmlTemplet;
class BiUp {
    constructor(face, isReserveRecall, link, mid, uname) {
        this.face = face;          // 用户头像链接
        this.isReserveRecall = isReserveRecall; // 是否保留召回标志，通常是一个布尔值
        this.link = link;          // 用户主页链接
        this.mid = mid;            // 用户ID
        this.uname = uname;        // 用户名
    }
    getDetails() {
        return `User Name: ${this.uname}, User ID: ${this.mid}, Link: ${this.link}`;
    }

    getLiveUpItemDom() {
        var htmlTemplet = singleUpHtmlTemplet;
        // 创建 DOMParser 对象
        const parser = new DOMParser();
        var doc = parser.parseFromString(htmlTemplet, 'text/html');
        //http -> https 防报错
        doc.querySelector("a").href = updateProtocol(this.link) + "?live_from=82002"; // 链接后还有 live_from 来源参数，可以不添加
        //图像 @84w_84裁剪成84*84像素
        doc.querySelector("picture :nth-child(1)").srcset = updateProtocol(this.face) + "@84w_84h.avif";
        doc.querySelector("picture :nth-child(2)").srcset = updateProtocol(this.face) + "@84w_84h.webp";
        doc.querySelector("picture :nth-child(3)").srcset = updateProtocol(this.face) + "@84w_84h";
        doc.querySelector(".up-name").textContent = this.uname;
        return doc;
    }

}
(function () {
    'use strict';
    ups = getLiveUpList();
    let hasInitialized = false;

window.addEventListener("load", async () => {
    const dynamicEle = await waitForElement("ul.right-entry > li:nth-child(4)", 80000);
    
    dynamicEle.addEventListener("mouseenter", function firstHoverHandler() {
        if (!hasInitialized) {
            hasInitialized = true;
            dynamicEle.removeEventListener('mouseenter', firstHoverHandler);
            
            loadLivingUp().then(() => {
                dynamicEle.addEventListener("mouseenter", function () {
                    console.log("mouseenter--55");
                    startChecking();
                });

                dynamicEle.addEventListener("mouseleave", function () {
                    clearInterval(currentIntervalId);
                });
                
                // 触发首次检查
                startChecking();
            });
        }
    });
});
    // console.log(ups);
    // Your code here...
})();
async function getLiveUpList() {
    console.log("获取直播UP主列表");
    const url = live_up_list_url;
    
    try {
        // 1. 等待网络响应
        const response = await fetch(url, {
            method: 'GET',
            credentials: 'include',
            headers: { 'Content-Type': 'application/json; charset=utf-8' }
        });
        
        // 2. 等待JSON解析
        const data = await response.json();
        
        // 3. 检查响应状态
        if (data.code !== 0) {
            console.log("没有直播UP主");
            return [];
        }
        
        // 4. 处理数据并返回
        return data.data.items.map(item => 
            new BiUp(
                item.face,
                item.is_reserve_recall,
                item.link,
                item.mid,
                item.uname
            )
        );
    } catch (error) {
        console.error('获取直播UP主失败:', error);
        return [];
    }
}
function optimizeLiveUpList(ups) {
    const livingUpList = document.querySelector('.living-up-list');
    livingUpList.style.flexWrap = 'wrap'; // 使用属性方式设置样式，更高效
    livingUpList.innerHTML = '';

    // 检查ups是否为Promise
    if (ups instanceof Promise) {
        // 如果是Promise，解析后处理
        ups.then((array) => {
            renderItems(array);
        }).catch((error) => {
            console.error('An error occurred while fetching data:', error);
        });
    } else if (Array.isArray(ups)) {
        // 如果已经是数组，直接处理
        renderItems(ups);
    } else {
        console.error('ups must be an array or a Promise that resolves to an array.');
    }
}
async function loadLivingUp() {
    // 2024-12-26 这里获取单个直播up元素的html模板，根本解决bug
    const singleUpHtml = await waitForElement('.living-up-list>a:nth-child(1)',
        5000,
        "ul.right-entry > li:nth-child(4)");
    console.log("模板:--", singleUpHtml);
    singleUpHtmlTemplet = singleUpHtml ?
        singleUpHtml.outerHTML :
        `
        <a data-v-e789ddd2="" class="up-item" target="_blank" data-mod="top_right_bar_window_dynamic" data-idx="content"
            data-ext="click" href="https://live.bilibili.com/21587367?live_from=82002" style="transform: translateX(0px);">
            <div data-v-e789ddd2="" class="up-avatar">
                <picture data-v-e789ddd2="" class="v-img up-avatar__img">
                    <source srcset="//i0.hdslb.com/bfs/face/57550946b06a4a9c24a70a1b7159c25ad7bdf383.jpg@84w_84h.avif"
                        type="image/avif">
                    <source srcset="//i0.hdslb.com/bfs/face/57550946b06a4a9c24a70a1b7159c25ad7bdf383.jpg@84w_84h.webp"
                        type="image/webp"><img
                        src="//i0.hdslb.com/bfs/face/57550946b06a4a9c24a70a1b7159c25ad7bdf383.jpg@84w_84h" alt="" loading="lazy"
                        onload="" onerror="typeof window.imgOnError === 'function' &amp;&amp; window.imgOnError(this)">
                </picture>
            </div>
            <div data-v-e789ddd2="">
                <div data-v-e789ddd2="" class="up-name">老蒋巨靠谱</div>
            </div>
        </a>
        `
    optimizeLiveUpList(ups);
}

/**
 * 等待目标元素出现在DOM中
 * @param {string} selector - 要查询的CSS选择器
 * @param {number} [timeout=2000] - 超时时间（毫秒）
 * @returns {Promise<Element|null>} 目标元素（超时返回null）
 */

function waitForElement(selector, timeout = 2000, parentSelector) {
    return new Promise((resolve) => {
        // 如果元素已存在，直接返回
        const element = document.querySelector(selector);
        const parentElement = parentSelector?
            document.querySelector(parentSelector):
            document.documentElement;
        if (element) {
            resolve(element);
            return;
        }
        if (!parentElement) {
            resolve(null);
            console.log("parentElement不存在");
            return;
        }
        let observer;
        const timer = setTimeout(() => {
            observer?.disconnect();
            resolve(null);
        }, timeout);

        // 配置观察选项
        const config = { childList: true, subtree: true };
        observer = new MutationObserver((mutations) => {
            for (const mutation of mutations) {
                const targetElement = document.querySelector(selector);
                if (targetElement) {
                    clearTimeout(timer);
                    observer.disconnect();
                    resolve(targetElement);
                    return;
                }
            }
        });

        // 开始观察整个文档
        observer.observe(parentElement, config);
    });
}

async function optimizeLiveUpList01(target) {
    await new Promise(resolve => setTimeout(resolve, 100));
    // 创建 mouseleave 事件
    const mouseLeaveEvent = new MouseEvent('mouseleave', {
        bubbles: false,  // 阻止事件冒泡
        cancelable: true,
        view: window
    });
    // 触发 mouseleave 事件，立即取消 mouseenter 状态
    target.dispatchEvent(mouseLeaveEvent);
    await new Promise(resolve => setTimeout(resolve, 1500));
    if (ups.length > 0) {
        optimizeLiveUpList(ups);
    }
}
function updateProtocol(url) {
    // 检查字符串是否以 "http:" 开头
    if (url.startsWith('http:')) {
        // 替换 "http:" 为 "https:"
        return url.replace('http:', 'https:');
    } else {
        // 如果不是以 "http:" 开头，则直接返回原字符串
        return url;
    }
}
async function startChecking() {
    const ups = await getLiveUpList();//await已经解析promise为数组
    optimizeLiveUpList(ups); // 请求成功时运行优化函数
}
// 抽离渲染逻辑到单独的函数
function renderItems(array) {
    let livingUpList = document.querySelector('.living-up-list');
    array.forEach((element, index) => {
        const linkElement = element.getLiveUpItemDom().querySelector('a');
        if (linkElement) {
            livingUpList.appendChild(linkElement);
        } else {
            console.warn(`Element at index ${index} does not contain an 'a' tag.`);
        }
    });
}